#include "WebcamWidget.h"

#include "CamWhore.h"

WebcamWidget::WebcamWidget(QWidget* parent)
: QGLWidget(), m_webcam(0), m_textureId(0), m_shadersSupported(false)
{
}

WebcamWidget::~WebcamWidget()
{
	glDeleteTextures(1, &m_textureId);
}

/*
void WebcamWidget::setEffect(const QString& filename)
{
	if(m_currentEffect)
		delete m_currentEffect;

	EffectListLoader loader;
	m_currentEffect = loader.load(filename, , this);
}
*/

void WebcamWidget::setWebcam(const Webcam* webcam)
{
	m_webcam = webcam;
}

void WebcamWidget::initializeGL()
{
	// Load the effects
	long long freq;
	QueryPerformanceFrequency((LARGE_INTEGER*)&freq);

	m_timerFreq = 1.0f / float(freq);

	long long start;
	QueryPerformanceCounter((LARGE_INTEGER*)&start);

	m_timerStart = float(start);

	m_shadersSupported = QGLShaderProgram::hasOpenGLShaderPrograms(this->context());
	if(m_shadersSupported)
	{
		//m_currentEffect->loadShader(context());
	}
	else
	{
		QMessageBox message;
		message.setText("CamWhore has detected that your system\n"
						"does not support OpenGL shaders (GLSL).\n\n"
						"This program will still work without them\n"
						"but will support any of the effects.\n\n"
						"If you believe this is a mistake please try\n"
						"updating your graphics drivers or shooting\n"
						"me (juliusparishy@gmail.com) an email.\n\n\n"
						"Sorry!");

		message.exec();
	}

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	glOrtho(0.0f, float(this->geometry().width()), 0.0f, float(this->geometry().height()), -1.0f, 1.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void WebcamWidget::paintGL()
{
	if(m_webcam && m_webcam->currentFrame())
	{
		// Update the timer
		m_timerLast = m_timerCurr;

		long long curr;
		QueryPerformanceCounter((LARGE_INTEGER*)&curr);

		m_timerCurr = float(curr);

		float elapsed = (float(m_timerCurr) - m_timerStart) * m_timerFreq;
		float delta = (float(m_timerCurr) - m_timerLast) * m_timerFreq;
/*
		foreach(EffectVariable var, m_currentEffect->effectVariables())
		{
			if(var.shouldUpdateEveryFrame)
			{
				if(var.isStandardValue)
				{
					if(var.standardValue == StandardValue::DeltaTime)
					{
						int pos = m_currentEffect->program()->uniformLocation(var.name);
						m_currentEffect->program()->setUniformValue(pos, delta);
					}
					else if(var.standardValue == StandardValue::ElapsedTime)
					{
						int pos = m_currentEffect->program()->uniformLocation(var.name);
						m_currentEffect->program()->setUniformValue(pos, elapsed);
					}
				}
			}
		}
*/
		const WebcamFrame* frame = m_webcam->currentFrame();

		// TODO: Use PBO's instead of glTexSubImage2D

		glEnable(GL_TEXTURE_2D);

		if(!m_textureId)
		{
			glGenTextures(1, &m_textureId);
			glBindTexture(GL_TEXTURE_2D, m_textureId);

			glTexImage2D(GL_TEXTURE_2D, 0, 4, frame->mediaType.width, frame->mediaType.height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, frame->data);

			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		}
		else	
		{
			glBindTexture(GL_TEXTURE_2D, m_textureId);
			
			glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frame->mediaType.width, frame->mediaType.height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, frame->data);
		}

		if(m_shadersSupported)
		{
		/*
			if(m_currentEffect)
			{
				m_currentEffect->makeActive();
			}
			else
			{
				QMessageBox message;
				message.setText("No current effect set!");
				message.exec();

			}
		*/
		}

		glBegin(GL_TRIANGLE_STRIP);

		// Swap horizontal vertices to mirror image on the x axis 
		//         New              Original
		glTexCoord2f(0.0f, 1.0f);
		glVertex2f(640.0f, 480.0f); // 0.0f, 480.0f

		glTexCoord2f(0.0f, 0.0f);
		glVertex2f(640.0f, 0.0f); // 0.0f, 0.0f

		glTexCoord2f(1.0f, 1.0f);
		glVertex2f(0.0f, 480.0f); // 640.0f, 480.0f

		glTexCoord2f(1.0f, 0.0f);
		glVertex2f(0.0f, 0.0f); // 640.0f, 0.0f

		glEnd();
	}

	update();
}

void WebcamWidget::sliderMoved(int value)
{
	/*
	QObject* s = sender();
	QSlider* slider = static_cast<QSlider*>(s);
	QWidget* parent = slider->parentWidget();
	// Find the variable
	foreach(EffectVariable var, m_currentEffect->effectVariables())
	{
		if(var.guiControl.widget == parent)
		{
			int varLoc = m_currentEffect->program()->uniformLocation(var.name);

			if(var.value.type == EffectVariableType::Float)
			{
				var.value.floatValue = float(value);
				m_currentEffect->program()->setUniformValue(varLoc, var.value.floatValue);
			}
			else if(var.value.type == EffectVariableType::Int)
			{
				var.value.intValue = value;
				m_currentEffect->program()->setUniformValue(varLoc, var.value.intValue);
			}
		}
	}
	*/
}

void WebcamWidget::buttonPressed(QAbstractButton* button)
{
	/*
	QObject* s = sender();

	QButtonGroup* group = button->group();
	int id = group->id(button);

	QWidget* parent = button->parentWidget();
	foreach(EffectVariable var, m_currentEffect->effectVariables())
	{
		if(var.guiControl.widget == parent)
		{
			int varLoc = m_currentEffect->program()->uniformLocation(var.name);

			id = -id - 2;

			if(var.value.type == EffectVariableType::Float)
			{
				var.value.floatValue = float(id);
				m_currentEffect->program()->setUniformValue(varLoc, var.value.floatValue);
			}
			else if(var.value.type == EffectVariableType::Int)
			{
				var.value.intValue = id;
				m_currentEffect->program()->setUniformValue(varLoc, var.value.intValue);
			}
		}
	}
	*/
}

void WebcamWidget::buttonPressed()
{

}